/* 
 * This file is part of the Coffee Survey Framework - http://coffee.codeplex.com
 */
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Xml;
using System.Collections.Generic;
using Coffee.SurveyControls.SurveyQuestions;

namespace Coffee.SurveyControls
{
    public class SurveyQuestionControlList : Dictionary<string, SurveyQuestionRow>
    {
    }
    /// <summary>
    /// Summary description for SurveyQuestionsTable
    /// </summary>
    public class SurveyQuestionsTable : SurveyControl
    {
        protected SurveyQuestionControlList surveyQuestionControls;
        SurveyQuestionsTable sqt;

        protected string errMessage;
        protected HtmlTable tbl = new HtmlTable();

        // REQUIRED: Constructor - just calls the base class that sets up coffee and configuration
        public SurveyQuestionsTable(SurveyManager coffee, XmlNode configuration)
            : base(coffee, configuration)
        {
            surveyQuestionControls = new SurveyQuestionControlList();
        }

        public SurveyQuestionsTable()
        {
            surveyQuestionControls = new SurveyQuestionControlList();
        }


        public SurveyQuestionControlList SurveyQuestionControls
        {
            get { return surveyQuestionControls; }
        }

        public XmlNode Configuration { get { return configuration; } }

        protected string evenRowClass = "surveytable-row surveytable-row-even";
        protected string oddRowClass = "surveytable-row surveytable-row-odd";
        protected string headerClass = "surveytable-row surveytable-row-header";

        public override object FindControl(string id)
        {
            if (surveyQuestionControls.ContainsKey(id))
            {
                return surveyQuestionControls[id];
            }
            return base.FindControl(id);
        }

        protected virtual string GetQuestionHeader()
        {
            return "Question";
        }

        protected virtual string GetColumn2Header()
        {
            return "Current Answer";
        }

        protected virtual string GetColumn1Header()
        {
            return "Previous Answer";
        }

        protected virtual XmlNodeList GetQuestions()
        {
            return configuration.SelectNodes("configuration/question");
        }

        protected virtual string GetQuestionID(XmlNode question)
        {
            return question.Attributes["id"].Value;
        }

        // called by the constructor
        public override void Initialize()
        {
            bool bShowheader = true;
            bool bShowprev = true;

            XmlNodeList xOptions = configuration.SelectNodes("configuration/option");
            foreach (XmlNode xOption in xOptions)
            {
                string value = xOption.Attributes["value"].Value;
                switch (xOption.Attributes["name"].Value)
                {
                    case "header":
                        bShowheader = (value == "yes");
                        break;
                    case "prevyear":
                        bShowprev = (value == "yes");
                        break;
                }
            }

            tbl.Width = "100%";
            if (bShowheader)
            {
                HtmlTableRow r = new HtmlTableRow();
                HtmlTableCell c1 = new HtmlTableCell();
                HtmlTableCell c2 = null;
                HtmlTableCell c3 = new HtmlTableCell();

                XmlNodeList xColumns = configuration.SelectNodes("configuration/columns/column");
                foreach (XmlNode xColumn in xColumns)
                {
                    string style;
                    HtmlTableCell c = null;
                    switch (xColumn.Attributes["id"].Value)
                    {
                        case "question":
                            c = c1;
                            break;
                        case "previous":
                            c = c2;
                            break;
                        case "current":
                            c = c3;
                            break;
                    }
                    XmlNode xStyle = xColumn.SelectSingleNode("style");
                    if (xStyle != null && c != null)
                    {
                        c.Style.Value = xStyle.InnerText.Trim();
                    }
                }

                Label l1 = new Label();
                Label l2;
                Label l3 = new Label();

                l1.Text = GetQuestionHeader();
                l3.Text = GetColumn2Header();

                c1.Controls.Add(l1);

                if (bShowprev)
                {
                    c2 = new HtmlTableCell();
                    l2 = new Label();

                    l2.Text = GetColumn1Header();
                    c2.Controls.Add(l2);
                    c2.Attributes["class"] = headerClass;
                }

                c3.Controls.Add(l3);

                c1.Attributes["class"] = headerClass;
                c3.Attributes["class"] = headerClass;

                c1.Width = "40%";
                if (bShowprev)
                    c2.Width = "30%";
                c3.Width = "30%";

                r.Cells.Add(c1);
                if (bShowprev) r.Cells.Add(c2);
                r.Cells.Add(c3);

                tbl.Rows.Add(r);
            }

            // we're trying to get away from hard-coded numbers...
            // need an alternative to this, perhaps a lookup table on the db...
            //if (configuration.ParentNode.Attributes["navigationid"] != null)
            //{
            //    string navId = configuration.ParentNode.Attributes["navigationid"].Value;
            //    Questions = DataSources.GetQuestions(int.Parse(navId));
            //}

            XmlNodeList questions = GetQuestions();

            ScriptManager.AddShowHideDependents(Page);

            int i = 0;
            foreach (XmlNode question in questions)
            {
                string id = GetQuestionID(question);

                SurveyQuestionRow sqctl = SurveyQuestionRowFactory.Create(this, question);

                SurveyQuestionControls.Add(id, sqctl);

                sqctl.Attributes["class"] = (i % 2 == 0) ? evenRowClass : oddRowClass;

                i++;

                tbl.Rows.Add(sqctl);
            }

            tbl.Attributes["class"] = "surveytable";

            this.Controls.Add(tbl);

        }

        public override void LoadData()
        {
            if (_mapper != null)
            {
                _mapper.Load();
            }

            foreach (SurveyQuestionRow ctl in SurveyQuestionControls.Values)
            {
                ctl.Locked = Locked;
                try
                {
                    ctl.LoadDynamicData();
                    ctl.LoadData();
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("Error occured while Loading control '{0}': {1}", ctl.Configuration.Attributes["id"].Value, ex.Message), ex);
                }
            }

        }

        public override void LoadDynamicControls()
        {
            if (_mapper != null)
            {
                _mapper.Load();
            }

            foreach (SurveyQuestionRow ctl in SurveyQuestionControls.Values)
            {
                if (ctl.IsDynamic)
                {
                    try
                    {
                        ctl.LoadDynamicData();
                    }
                    catch (Exception ex)
                    {
                        throw new Exception(string.Format("Error occured while Loading control '{0}': {1}", ctl.Configuration.Attributes["id"].Value, ex.Message), ex);
                    }
                }
            }

        }

        public override void WireEvents(bool isCallback)
        {
            foreach (SurveyQuestionRow ctl in SurveyQuestionControls.Values)
            {
                if (isCallback)
                    ctl.SetupCallBackHandlers();
                else
                    ctl.SetupClientEventHandlers(Page);
            }
        }

        protected override bool CheckIsDirty()
        {
            bool isDirty = false;
            foreach (SurveyQuestionRow ctl in SurveyQuestionControls.Values)
            {
                isDirty |= ctl.IsDirty;
            }

            return isDirty;
        }

        public override void SaveData()
        {
            if (!locked)
            {
                if (Validate())
                {
                    foreach (SurveyQuestionRow ctl in SurveyQuestionControls.Values)
                    {
                        ctl.SaveData();
                    }

                    if (_mapper != null)
                    {
                        _mapper.Update();
                    }
                }
            }
        }


        public static bool ValidateControl(string type, Control curr)
        {
            if (type == "required")
            {
                if (curr.GetType() == typeof(TextBox))
                {
                    if (((TextBox)curr).Text.Trim().Length == 0)
                        return false;
                }
            }
            return true;
        }

        // This is just so validation can be tested
        // Look into more complex validation methods, such as those that
        // allow validation errors to bubble up and be caught by a parent
        // validator, for custom handling
        // Think exceptions.  Well, we can probably throw a custom Exception and handle it that way?
        public override bool Validate()
        {
            bool isValid = true;
            XmlNode validation = configuration.SelectSingleNode("validation");

            if (validation != null)
            {
                XmlNodeList validationRules = validation.SelectNodes("rules/*");

                if (validationRules.Count > 0)
                {
                    foreach (XmlNode rule in validationRules)
                    {
                        string controlName = rule.SelectSingleNode("text()").Value;
                        XmlNode config = configuration.SelectSingleNode("question[@id='" + controlName + "']");

                        bool valid = true;

                        valid &= ValidateControl(rule.Name, surveyQuestionControls[controlName].CurrentControl);

                        valid &= surveyQuestionControls[controlName].Validate();

                        if (!valid)
                        {
                            Control q = SurveyControls[controlName + "-ques"];
                            Label asterisk = new Label();
                            asterisk.Text = " <strong>*</strong>";
                            asterisk.ForeColor = System.Drawing.Color.Red;
                            q.Parent.Controls.Add(asterisk);
                        }

                        isValid &= valid;
                    }
                }

                if (!isValid)
                {
                    // some default text
                    errMessage = "There was a problem validating this page. Please try again";

                    XmlNode errMsg = validation.SelectSingleNode("message");
                    if (errMsg != null)
                    {
                        errMessage = errMsg.SelectSingleNode("text()").Value;
                    }

                    HtmlTableRow errRow = new HtmlTableRow();
                    HtmlTableCell errCell = new HtmlTableCell();
                    Label errLabel = new Label();
                    errCell.Align = "center";
                    errLabel.Text = "<strong>" + errMessage + "</strong>";
                    errLabel.Attributes["class"] = "errortext";
                    errLabel.ForeColor = System.Drawing.Color.Red;
                    errCell.ColSpan = 3;
                    errCell.Controls.Add(errLabel);
                    errRow.Controls.Add(errCell);
                    tbl.Rows.Add(errRow);
                }

            }


            return isValid;
        }

    }
}